#include "reportbuilder.h"

#include "../documents/data/reportdata.h"
#include "../documents/data/simgraphicdata.h"
#include "../documents/swpreportdocument.h"
#include "../editors/items/swpsimactivitygraphicitem.h"

#include <coremimetypes.h>
#include <icontainerdocument.h>
#include <journal.h>
#include <mimetypemanager.h>
#include <wfnet.h>

#include <QtCore/QDateTime>
#include <QtCore/qmath.h>
#include <QtGui/QStandardItemModel>

using namespace swp;
using namespace wfnet;

ReportBuilder* reportBuilder = 0;

ReportBuilder* ReportBuilder::getInstance()
{
    if (reportBuilder == 0)
    {
        reportBuilder = new ReportBuilder();
    }

    return reportBuilder;
}

void ReportBuilder::destroy()
{
    delete reportBuilder;
    reportBuilder = 0;
}

QSharedPointer<SwpReportDocument> ReportBuilder::build(
    const QSharedPointer<SwpSimulationCaseDocument>& document)
{
    QDateTime current = QDateTime::currentDateTime();

    const QString timeStamp = current.toString("ddMMyyyyhhmmss");

    SwpReportDocument* report = new SwpReportDocument(
        QString("ReportDocument_%1").arg(timeStamp),
        MimeTypeManager::getInstance()->mimeType(REPORT_MIMETYPE),
        document->container(), false);

    SimGraphicData* data = dynamic_cast<SimGraphicData* >(document->data());
    ReportData* repData = dynamic_cast<ReportData* >(report->data());

    Q_ASSERT(data != 0 && repData != 0); // bad data type

    BatchJournal* journal = data->net()->journal();
    const QHash<nid, const SwpSimActivityGraphicItem* > mapping =
        data->m_reportMapping;

    repData->m_timeStamp = current.toString("dd.MM.yyyy hh:mm:ss");

    for (uint i = 1; i <= journal->runs(); ++i)
    {
        foreach (const nid& id, mapping.keys())
        {
            const int execs = journal->executions(i, id);

            makeExecEntry(i, mapping[id], execs, repData);
        }

        foreach (const nid& id, data->net()->places())
        {
            const TypeValue tokens = journal->tokens(i, id);
            makeTokenEntry(i, id, tokens, data->m_endPlace == id, repData);
        }

        QList<QStandardItem*> row;

        row.append(new QStandardItem(QString::number(i)));
        row.append(new QStandardItem(QString::number(journal->steps(i))));

        repData->m_steps->appendRow(row);
    }

    return QSharedPointer<SwpReportDocument>(report);
}

ReportBuilder::ReportBuilder()
{

}

ReportBuilder::~ReportBuilder()
{

}

void ReportBuilder::makeExecEntry(uint run,
    const SwpSimActivityGraphicItem* item, int execs, ReportData* data)
{
    QList<QStandardItem* > row;

    row.append(new QStandardItem(QString::number(run)));
    row.append(new QStandardItem(item->propertyValue("name").toString()));
    row.append(new QStandardItem(item->propertyValue("cost").toString()));

    QStandardItem* executions = new QStandardItem();

    QList<QStandardItem* > executionsRow;

    for (int i = 0; i < execs; ++i)
    {
        const int dur = item->propertyValue("duration").toInt();
        int t = dur == 0 ? 0 :
            qCeil(0.5 + qLn(1 - ((double)qrand()/RAND_MAX))/((double)-1/dur));

        executionsRow.append(new QStandardItem(QString::number(t)));
    }

    executions->appendRow(executionsRow);

    row.append(executions);

    data->m_executions->appendRow(row);
}

void ReportBuilder::makeTokenEntry(uint run, const net::nid& id,
    const core::TypeValue& tokens, bool isEndPlace, ReportData* data)
{
    QList<QStandardItem*> row;

    row.append(new QStandardItem(QString::number(run)));
    row.append(new QStandardItem(id.toString()));
    row.append(new QStandardItem(tokens));
    row.append(new QStandardItem(QString::number(isEndPlace)));

    data->m_tokens->appendRow(row);
}
